/*
*
* ████████╗░█████╗░███████╗██████╗░░█████╗░
* ╚══██╔══╝██╔══██╗██╔════╝██╔══██╗██╔══██╗
* ░░░██║░░░██║░░██║█████╗░░██████╦╝███████║
* ░░░██║░░░██║░░██║██╔══╝░░██╔══██╗██╔══██║
* ░░░██║░░░╚█████╔╝██║░░░░░██████╦╝██║░░██║
* ░░░╚═╝░░░░╚════╝░╚═╝░░░░░╚═════╝░╚═╝░░╚═╝
* 
*  :: 九方通逊-Henry ::   Copyright©2020 tofba.com  
* 
*/
package com.lmexpress.service.impl;

import java.io.File;
import java.net.URL;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.lmexpress.enums.ApiCredential;
import com.lmexpress.enums.ApiOrderError;
import com.lmexpress.enums.LabelFormat;
import com.lmexpress.enums.LabelSize;
import com.lmexpress.enums.LabelSuffix;
import com.lmexpress.orm.openapi.ExpressOrderApi;
import com.lmexpress.orm.openapi.OrderInvoice;
import com.lmexpress.orm.rest.ApiLabelResponse;
import com.lmexpress.orm.rest.ApiOrderResponse;
import com.lmexpress.orm.webservice.xms.CreateOrderRequest;
import com.lmexpress.orm.webservice.xms.CreateOrderResponse;
import com.lmexpress.orm.webservice.xms.DeclareItem;
import com.lmexpress.orm.webservice.xms.OrderOnlineService;
import com.lmexpress.orm.webservice.xms.OrderOnlineServiceProxy;
import com.lmexpress.orm.webservice.xms.PrintOrderRequest;
import com.lmexpress.orm.webservice.xms.PrintOrderResponse;
import com.lmexpress.service.ApiService;
import com.lmexpress.util.ApiUtil;

/**
 * 
 * <XMS系统>
 * 
 * @author Henry(fba02)
 * @version [版本号, 2020-12-09]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class XMSClient implements ApiService {
    private static final Logger LOGGER = LoggerFactory.getLogger(XMSClient.class);
    private OrderOnlineService service;   
    
    @Override
    public ApiOrderResponse preProcessCreateOrder(ExpressOrderApi expressOrderApi) {
        return null;
    }
    
    @Override
    public String mapping(ExpressOrderApi expressOrderApi) {
        CreateOrderRequest req = new CreateOrderRequest();
        req.setOrderNo(expressOrderApi.getCustomerInvoiceCode()); // 客户单号
        Map<String, String> apiCredentials = expressOrderApi.getApiCredentials();
        req.setTransportWayCode(apiCredentials.get(ApiCredential.XMS_PRODUCT_CODE.getKey()));// 运输方式代码
        req.setCargoCode("W");// 货物类型(W包裹/D文件).必填
        req.setInsured("N"); // 购买保险(投保：Y，不投保：N).必填
        req.setWeight(expressOrderApi.getWeight());// 货物预报重量.必填；0<=value
        req.setGoodsCategory("O");// 物品类别(G/D/S/R/O).必填
        req.setGoodsDescription("other");// 物品类别内容
        req.setPieces(Long.valueOf(expressOrderApi.getOrderPiece() == null ? 1L : expressOrderApi.getOrderPiece()));
        // 收货人
        req.setDestinationCountryCode(expressOrderApi.getCountryCode()); // 目的国家二字简码.必填
        req.setConsigneeCompanyName(expressOrderApi.getConsigneeCompanyName());// 收件人公司名称.length<=100
        req.setConsigneeName(expressOrderApi.getConsigneeName()); // 收件人姓名. length<=100
        req.setConsigneeTelephone(expressOrderApi.getConsigneeTelephone()); // 收件人电话号码.length<=32
        req.setConsigneeMobile(expressOrderApi.getConsigneeMobile()); // 收件人手机号码.length<=32
        req.setStreet(expressOrderApi.getConsigneeAddress()); // 街道.必填；length<=200
        req.setCity(expressOrderApi.getConsigneeCity()); // 城市.必填；length<=60
        req.setProvince(expressOrderApi.getConsigneeState()); // 省/州.必填；length<=60
        req.setConsigneePostcode(expressOrderApi.getConsigneePostCode()); // 收件人邮编.length<=10
        // 发货人
        req.setOriginCountryCode(DEFAULT_SHIPPER_COUNTRY_CODE);
        req.setShipperCompanyName(expressOrderApi.getShipperCompanyName()); // 发件人公司名称.length<=100
        req.setShipperName(expressOrderApi.getShipperName()); // 发件人姓名.length<=100
        req.setShipperTelephone(expressOrderApi.getShipperTelephone()); // 发件人电话号码.length<=32
        req.setShipperMobile(expressOrderApi.getShipperTelephone()); // 发件人手机号码.length<=32
        req.setShipperAddress(expressOrderApi.getShipperAddress1()); // 发件人地址.length<=200
        // 报关明细
        List<OrderInvoice> orderInvoices = expressOrderApi.getOrderInvoices();
        if (CollectionUtils.isNotEmpty(orderInvoices)) {
            Double weight = expressOrderApi.getWeight();
            Double totalWeight = 0D;
            DeclareItem[] declareItems = new DeclareItem[orderInvoices.size()];
            DeclareItem declareItem = null;
            OrderInvoice orderInvoice = null;
            for (int i = 0; i < orderInvoices.size(); i++) {
                orderInvoice = orderInvoices.get(i);
                declareItem = new DeclareItem();
                declareItem.setName(orderInvoice.getSkuNameEn()); // 申报品名.必填；0<length<100
                Double invoiceWeight = orderInvoice.getInvoiceWeight();
                declareItem.setNetWeight(invoiceWeight == null ? weight / orderInvoices.size() : invoiceWeight);// 净重(kg).必填;0<=value
                declareItem.setUnitPrice(orderInvoice.getPurchasingPrice()); // 单价.必填；0<value
                declareItem.setPieces(Long.valueOf(orderInvoice.getInvoicePcs())); // 件数.必填；1<value
                declareItem.setProductMemo(orderInvoice.getSkuCode());
                declareItems[i] = declareItem;
                invoiceWeight += invoiceWeight;
            }
            if (null == weight || null != weight && weight < 0.001D) {
                req.setWeight(totalWeight);
            }
            req.setDeclareItems(declareItems);
        }
        return new Gson().toJson(req);
    }
    
    @Override
    public ApiOrderResponse createOrder(ExpressOrderApi expressOrderApi) {
        Map<String, String> apiCredentials = expressOrderApi.getApiCredentials();
        if (null == service) {
            service = new OrderOnlineServiceProxy(apiCredentials.get(ApiCredential.XMS_ENDPOINT.getKey()));
        }
        try {
            Gson gson = new Gson();
            String orderJson = mapping(expressOrderApi);
            LOGGER.info("xms.shipment.request:{}", orderJson);
            // 创建并预报订单
            CreateOrderRequest req = gson.fromJson(orderJson, new TypeToken<CreateOrderRequest>() {
            }.getType());
            CreateOrderResponse res = service.createAndAuditOrder(apiCredentials.get(ApiCredential.XMS_USER_TOKEN.getKey()), req);
            if (null == res) {
                return new ApiOrderResponse(false, null, ApiOrderError.SERVICE_NO_DATA_RETURN.getMessage(), true, null);
            }
            if (res.getSuccess()) {
                ApiOrderResponse apiOrderResponse = new ApiOrderResponse();
                apiOrderResponse.setSuccess(true);
                apiOrderResponse.setReferenceNo(expressOrderApi.getCustomerInvoiceCode());
                String trackingNumber = res.getTrackingNo();
                apiOrderResponse.setTrackNumber(trackingNumber);
                String thirdPartyorderNo = String.valueOf(res.getId());
                apiOrderResponse.setThirdPartyorderNo(thirdPartyorderNo);
                ApiLabelResponse apiLabelResponse = label(trackingNumber, apiCredentials);
                if (StringUtils.isNotBlank(apiLabelResponse.getLabelPath())) {
                    apiOrderResponse.setLabelUrl(apiLabelResponse.getLabelPath());
                    apiOrderResponse.setLmLabelUrl(apiLabelResponse.getRelativePath());
                }
                return apiOrderResponse;
            }
            return new ApiOrderResponse(false, null, res.getError().getErrorInfo(), gson.toJson(res));
        } catch (Exception e) {
            LOGGER.error("xms.shipment.exception", e);
            return new ApiOrderResponse(false, null, ApiOrderError.CREATE_ORDER_EXCEPTION.getMessage(), false, e.getMessage());
        }
    }
    
    @Override
    public ApiLabelResponse label(String trackingNumber, Map<String, String> apiCredentials) {
        PrintOrderRequest req = new PrintOrderRequest();
        req.setTrackingNo(trackingNumber);
        // printSelect:选择打印样式
        // 1 地址标签打印
        // 11 报关单
        // 2 地址标签+配货信息
        // 3 地址标签+报关单
        // 12 特殊100mm×100mm地址标签+配货信息+报关单
        // pageSizeCode:纸张尺寸，
        // "1"表示80.5mm × 90mm
        // "2"表示105mm × 210mm
        // "3"表示A4
        // "7"表示100mm × 150mm
        // "4"表示102mm × 76mm
        // "5"表示110mm × 85mm
        // "6"表示100mm × 100mm
        req.setPageSizeCode("7");
        req.setPrintSelect("3");
        req.setShowCnoBarcode("0");
        try {
            PrintOrderResponse res = service.printOrder(apiCredentials.get(ApiCredential.XMS_USER_TOKEN.getKey()), req);
            if (null != res && res.getSuccess()) {
                String pdfName = trackingNumber + LabelSuffix.PDF.getSuffix();
                // 当前月份
                String centrePath = ApiUtil.getCurrentDay() + File.separator;
                String relativePath = DEFAULT_LABEL_FOLDER + File.separator + centrePath;
                String folderPath = DEFAULT_LABEL_ROOT + relativePath;
                if (!new File(folderPath).exists()) {
                    new File(folderPath).mkdirs();
                }
                String fileUrl = folderPath + pdfName;
                String url = res.getUrl();
                ApiLabelResponse apiLabelResponse = new ApiLabelResponse(trackingNumber, url);
                try {
                    FileUtils.copyURLToFile(new URL(url), new File(fileUrl));
                    apiLabelResponse.setRelativePath(relativePath + pdfName);
                } catch (Exception e) {
                    LOGGER.error("xms.copy.url.to.file.exception", e);
                }
                apiLabelResponse.setLabelFormat(LabelFormat.PDF.getFormat());
                apiLabelResponse.setLabelSize(LabelSize.LABEL_10_15.getSize());
                return apiLabelResponse;
            }
            return new ApiLabelResponse(trackingNumber, null);
        } catch (Exception e) {
            LOGGER.error("xms.label.exception", e);
            return new ApiLabelResponse(trackingNumber, null);
        }
    }
    
    @Override
    public void tracking(String trackNumber, Map<String, String> configureMap) {
        
    }
    
    @Override
    public String trackNumber(String code, Map<String, String> configureMap) {
        return null;
    }
    
    @Override
    public ApiLabelResponse labelRender(String trackNumber, ExpressOrderApi expressOrderApi) {
        return null;
    }
    
    @Override
    public ApiLabelResponse label(String referenceNo, String trackNumber, Map<String, String> configureMap) {
        return null;
    }
}